package lion.dev.net;

import java.io.DataOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.net.HttpURLConnection;
import java.net.URL;
import java.net.URLEncoder;
import java.util.zip.GZIPInputStream;

import org.apache.commons.io.IOUtils;
import org.apache.commons.lang.StringUtils;

import lion.dev.lang.MapJ;
import lion.dev.text.charset.CharsetDetector;

/**
 * @author Helin
 * @date 2012-8-12
 * @desc 下载
 */
public class HttpUtil {

	public static Content get(String url, MapJ form, MapJ header) throws IOException {

		if (form != null) {
			url = buildURL(url, form);
		}

		URL theurl = new URL(url);
		HttpURLConnection conn = (HttpURLConnection) theurl.openConnection();
		if (header != null && !header.isEmpty()) {
			for (String key : header.keySet()) {
				conn.setRequestProperty(key, header.getString(key));
			}
		}
		conn.setDoInput(true);
		conn.setDoOutput(false);
		conn.setRequestMethod("GET");
		conn.setUseCaches(false);
		conn.setInstanceFollowRedirects(true);

		return readContent(conn);
	}

	public static Content post(String url, MapJ param) throws IOException {
		return post(url, param, null);
	}

	public static Content post(String url, MapJ param, MapJ header) throws IOException {

		String body = null;
		if (param != null && !param.isEmpty()) {
			StringBuilder builder = new StringBuilder();
			for (String key : param.keySet()) {
				builder.append("&").append(key).append("=").append(URLEncoder.encode(param.getString(key), "UTF-8"));
			}

			body = builder.toString();
			if (StringUtils.startsWith(body, "&")) {
				body = body.substring(1);
			}
		}
		return post(url, body, header);
	}

	public static Content post(String url, String body, MapJ header) throws IOException {

		URL theurl = new URL(url);
		HttpURLConnection conn = (HttpURLConnection) theurl.openConnection();
		if (header != null && !header.isEmpty()) {
			for (String key : header.keySet()) {
				conn.setRequestProperty(key, header.getString(key));
			}
		}
		conn.setDoInput(true);
		conn.setDoOutput(true);
		conn.setRequestMethod("POST");
		conn.setUseCaches(false);
		conn.setInstanceFollowRedirects(true);
		conn.setRequestProperty("Content-Type", "application/x-www-form-urlencoded");
		conn.setConnectTimeout(10 * 1000); // 10s
		conn.setReadTimeout(10 * 1000);
		if (StringUtils.isNotBlank(body)) {
			DataOutputStream dos = (DataOutputStream) conn.getOutputStream();
			dos.writeBytes(body);
			dos.flush();
			dos.close();
		}
		return readContent(conn);
	}

	public static String postString(String url, MapJ param, MapJ header) throws IOException {

		Content content = post(url, param, header);
		if (content != null) { return new String(content.getContent()); }

		return null;
	}

	public static String postString(String url, String body, MapJ header) throws IOException {

		Content content = post(url, body, header);
		if (content == null) { return null; }
		byte[] arr = content.getContent();
		String charset = CharsetDetector.detect(arr);
		return new String(arr, charset);
	}

	public static MapJ postJSON(String url, MapJ param, MapJ header) throws IOException {

		String content = postString(url, param, header);
		if (StringUtils.isNotBlank(content)) {
			try {
				return MapJ.fromJson(content);
			} catch (Exception e) {
			}
		}
		return null;
	}

	public static MapJ postJSON(String url, String json, MapJ header) throws IOException {

		Content content = post(url, json, header);
		if (content == null) { return null; }
		try {
			return MapJ.fromJson(new String(content.getContent()));
		} catch (Exception e) {
		}
		return null;
	}

	public static String getString(String url, MapJ form, MapJ header) throws IOException {

		byte[] arr = get(url, form, header).getContent();
		String charset = CharsetDetector.detect(arr);
		return new String(arr, charset);
	}

	public static MapJ getJSON(String url, MapJ form, MapJ header) throws IOException {

		String content = getString(url, form, header);
		if (StringUtils.isNotBlank(content)) { return MapJ.fromJson(content); }
		return new MapJ();
	}

	private static Content readContent(HttpURLConnection conn) throws IOException {

		Content content = new Content();
		try (InputStream is = conn.getInputStream()) {

			for (String key : conn.getHeaderFields().keySet()) {
				content.setHeader(key, conn.getHeaderField(key));
			}
			// GZIP
			String ce = content.getHeader("Content-Encoding");
			if (StringUtils.isNotBlank(ce) && ce.indexOf("gzip") > -1) {
				content.setContent(IOUtils.toByteArray(new GZIPInputStream(is)));
			} else {
				content.setContent(IOUtils.toByteArray(is));
			}
			return content;
		}
	}

	private static String buildURL(String url, MapJ param) {

		if (param == null) { return url; }
		StringBuilder builder = new StringBuilder();
		for (String key : param.keySet()) {
			builder.append("&" + key + "=" + param.getString(key));
		}

		String query = builder.toString();
		if (StringUtils.isBlank(query)) { return url; }

		if (url.indexOf("?") > 0) {
			url = url + query;
		} else {
			url += "?" + query.substring(1);
		}
		return url;
	}
}
